package com.oauth.google.server.orkut.service;

import javax.annotation.PostConstruct;

import oauth.signpost.OAuthConsumer;
import oauth.signpost.basic.DefaultOAuthConsumer;
import oauth.signpost.signature.HmacSha1MessageSigner;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Required;

import com.google.gdata.client.authn.oauth.GoogleOAuthHelper;
import com.google.gdata.client.authn.oauth.GoogleOAuthParameters;
import com.google.gdata.client.authn.oauth.OAuthHmacSha1Signer;
import com.google.gdata.client.authn.oauth.OAuthSigner;
import com.google.orkut.client.api.BirthdayNotificationTx;
import com.google.orkut.client.api.FriendTxFactory;
import com.google.orkut.client.api.GetFriendTx;
import com.google.orkut.client.api.GetProfileTx;
import com.google.orkut.client.api.GetScrapsTx;
import com.google.orkut.client.api.ProfileTxFactory;
import com.google.orkut.client.api.ScrapTxFactory;
import com.google.orkut.client.api.Transaction;
import com.google.orkut.client.api.UpdateProfileTx;
import com.oauth.common.server.beans.OAuthAccessToken;
import com.oauth.common.server.beans.OAuthConfigBean;
import com.oauth.common.server.beans.OAuthRequestToken;
import com.oauth.google.client.beans.orkut.OrkutBirthdayDetails;
import com.oauth.google.client.beans.orkut.OrkutFriendDetails;
import com.oauth.google.client.beans.orkut.OrkutScrapDetails;
import com.oauth.google.client.beans.orkut.OrkutUser;
import com.oauth.google.server.beans.GoogleOrkutBean;
import com.oauth.google.server.beans.GoogleRequestToken;
import com.oauth.google.server.constants.GoogleServiceType;
import com.oauth.google.server.orkut.util.AuthorizedChannel;
import com.oauth.google.server.orkut.util.OrkutUtil;
import com.oauth.service.generic.OAuthService;
import com.oauth.service.generic.beans.OAuthServiceBean;

public class OrkutOAuthServiceImpl implements OrkutOAuthService {

	private GoogleOAuthHelper mOAuthHelper;
	private OAuthSigner mSigner;
	private OAuthService mOAuthService;
	private OAuthConfigBean mOAuthConfigBean;

	@PostConstruct
	public void initialise() {
		mSigner = new OAuthHmacSha1Signer();
		mOAuthHelper = new GoogleOAuthHelper(mSigner);
	}

	/**
	 * @param pOAuthService
	 *            the oAuthService to set
	 */
	@Autowired(required = true)
	public void setOAuthService(OAuthService pOAuthService) {
		mOAuthService = pOAuthService;
	}

	/**
	 * @param pOAuthConfigBean
	 *            the oAuthConfigBean to set
	 */
	@Required
	public void setOAuthConfigBean(OAuthConfigBean pOAuthConfigBean) {
		mOAuthConfigBean = pOAuthConfigBean;
	}

	private GoogleOAuthParameters getOAuthParameters() {
		GoogleOAuthParameters oauthParameters = new GoogleOAuthParameters();
		oauthParameters.setOAuthConsumerKey(mOAuthConfigBean.getConsumerKey());
		oauthParameters.setOAuthConsumerSecret(mOAuthConfigBean.getConsumerSecret());
		oauthParameters.setScope(GoogleServiceType.Orkut.getScope());
		return oauthParameters;
	}

	@Override
	public OAuthAccessToken getAccessTokenFromDB(Long pMemberId) throws Exception {
		OAuthServiceBean token = null;
		token = mOAuthService.getToken(pMemberId, GoogleOrkutBean.class);
		if (token != null) {
			return new OAuthAccessToken(token.getAccessToken(), token.getAccessTokenSecret());
		}
		return null;
	}

	@Override
	public OAuthAccessToken getAccessTokenFromRequestToken(OAuthRequestToken pRequestToken,
			String pQueryString) throws Exception {
		GoogleOAuthParameters oauthParameters = getOAuthParameters();
		mOAuthHelper.getOAuthParametersFromCallback(pQueryString, oauthParameters);
		oauthParameters.setOAuthToken(pRequestToken.getToken());
		oauthParameters.setOAuthTokenSecret(pRequestToken.getTokenSecret());
		// Get access token .
		String accessToken = mOAuthHelper.getAccessToken(oauthParameters);
		return new OAuthAccessToken(accessToken, oauthParameters.getOAuthTokenSecret());
	}

	@Override
	public GoogleRequestToken getRequestToken() throws Exception {
		GoogleOAuthParameters oauthParameters = getOAuthParameters();
		mOAuthHelper.getUnauthorizedRequestToken(oauthParameters);
		oauthParameters.setOAuthCallback(mOAuthConfigBean.getCallBackUrl());
		String authorizeUrl = mOAuthHelper.createUserAuthorizationUrl(oauthParameters);
		GoogleRequestToken oauthTokenBean = new GoogleRequestToken(oauthParameters.getOAuthToken(),
				oauthParameters.getOAuthTokenSecret(), authorizeUrl);
		return oauthTokenBean;
	}

	@Override
	public void persistAccessToken(OAuthAccessToken pAccessToken, Long pMemberId) throws Exception {
		GoogleOrkutBean serviceBean = new GoogleOrkutBean();
		serviceBean.setAccessToken(pAccessToken.getToken());
		serviceBean.setAccessTokenSecret(pAccessToken.getTokenSecret());
		serviceBean.setMemberId(pMemberId);
		// serviceBean.setTwitterId(twitter.getUserId());
		mOAuthService.persistToken(serviceBean); // persist in db for future
		// use.
	}

	private <T extends Transaction> T getTransaction(Long pMemberId, T pTx) throws Exception {
		OAuthConsumer oauthConsumer = getOAuthConsumer(pMemberId);
		new AuthorizedChannel().add(pTx).run(oauthConsumer);
		return pTx;
	}

	private OAuthConsumer getOAuthConsumer(Long pMemberId) throws Exception {
		OAuthAccessToken accessToken = getAccessTokenFromDB(pMemberId);
		OAuthConsumer oauthConsumer = new DefaultOAuthConsumer(mOAuthConfigBean.getConsumerKey(),
				mOAuthConfigBean.getConsumerSecret());
		oauthConsumer.setMessageSigner(new HmacSha1MessageSigner());
		oauthConsumer.setTokenWithSecret(accessToken.getToken(), accessToken.getTokenSecret());
		return oauthConsumer;
	}

	public OrkutFriendDetails getFriends(Long pMemberId) throws Exception {
		FriendTxFactory friendTxFactory = new FriendTxFactory();
		GetFriendTx getFriendsTx = friendTxFactory.getSelfFriends();
		getTransaction(pMemberId, getFriendsTx);
		return OrkutUtil.getOrkutFriends(getFriendsTx);
	}

	public OrkutBirthdayDetails getUpcomingBirthdays(Long pMemberId) throws Exception {
		FriendTxFactory friendTxFactory = new FriendTxFactory();
		BirthdayNotificationTx birthdayNotificationTx = friendTxFactory.getBirthdayNotification();
		getTransaction(pMemberId, birthdayNotificationTx);
		return OrkutUtil.getBirthdayNotifications(birthdayNotificationTx);
	}

	public OrkutScrapDetails getScraps(Long pMemberId) throws Exception {
		ScrapTxFactory scrapTxFactory = new ScrapTxFactory();
		GetScrapsTx getScrapsTx = scrapTxFactory.getSelfScraps();
		getTransaction(pMemberId, getScrapsTx);
		return OrkutUtil.getOrkutScraps(getScrapsTx);
	}

	public OrkutUser getLoggedInUserInfo(Long pMemberId) throws Exception {
		ProfileTxFactory profileFactory = new ProfileTxFactory();
		GetProfileTx getProfileTx = profileFactory.getSelfProfile();
		getTransaction(pMemberId, getProfileTx);
		OrkutUser user = OrkutUtil.getOrkutUser(getProfileTx.getProfile());
		getProfileTx = profileFactory.getSelfProfile().alsoGetStatus();
		getTransaction(pMemberId, getProfileTx);
		user.setStatus(getProfileTx.getProfile().getStatus());
		return user;
	}

	@Override
	public void updateStatus(String pText, Long pMemberId) throws Exception {
		ProfileTxFactory profileFactory = new ProfileTxFactory();
		UpdateProfileTx updateProfileTx = profileFactory.updateSelfProfile().setStatus(pText);
		getTransaction(pMemberId, updateProfileTx);
	}
}
